package com.example.config.simpleDynamicTask;

import cn.hutool.core.date.DateUtil;
import com.example.config.simpleDynamicTask.job.MyCronJob;
import com.example.config.simpleDynamicTask.job.MyTriggerJob;
import com.example.config.simpleDynamicTask.mapper.FakeCronMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ConcurrentTaskExecutor;
import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.CronTask;
import org.springframework.scheduling.config.ScheduledTaskHolder;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.config.TriggerTask;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.util.Assert;

import java.util.Date;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

/**
 * @author ZhengDing
 * @date 2022/4/10 0:28
 */
@Configuration
@EnableScheduling
@ConditionalOnExpression("true")
public class MySchedulingConfig implements SchedulingConfigurer {
    
    @Bean
    public Executor taskExecutor() {
        return Executors.newScheduledThreadPool(3);
    }
    
    @Autowired
    FakeCronMapper fakeCronMapper;
    
    // @Autowired
    // ScheduledTaskRegistrar taskRegistrar;
    
    // @Autowired
    // ScheduledTaskHolder scheduledTaskHolder;
    
    // @Autowired
    // TaskScheduler taskScheduler;
    
    // @Bean
    // TaskScheduler getConcurrentTaskScheduler() {
    //     return new ConcurrentTaskScheduler();
    // }
    
    // @Bean
    // TaskScheduler getThreadPoolTaskScheduler() {
    //     ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
    //     taskScheduler.setPoolSize(16);
    //     taskScheduler.setRemoveOnCancelPolicy(true);
    //     taskScheduler.setThreadNamePrefix("仙剑奇侠传-");
    //     taskScheduler.initialize();
    //     return taskScheduler;
    // }
    
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        
        // 默认的，SchedulingConfigurer 使用的是单线程的方式，如果需要配置多线程，则需要指定 PoolSize
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setPoolSize(16);
        taskScheduler.setRemoveOnCancelPolicy(true);
        taskScheduler.setThreadNamePrefix("仙剑奇侠传-");
        taskScheduler.initialize();
    
        // 默认的线程池,只有一个线程
        // ConcurrentTaskScheduler taskScheduler = new ConcurrentTaskScheduler();
        
        
        
        taskRegistrar.setTaskScheduler(taskScheduler);
        System.out.println("addCronTask ...");
    
        // cron 任务
        // CronTask
        // taskRegistrar.addCronTask(new MyCronJob(), "0/3 * * * * ?");
        // taskRegistrar.addCronTask(new CronTask(new MyCronJob(), "0/3 * * * * ?"));
        // taskRegistrar.addCronTask(new CronTask(new MyCronJob(), new CronTrigger("0/3 * * * * ?")));
    
        // FixedDelayTask
        // 特点是上一个任务执行完毕后计时器才开始跑, 计时器到期后开始下一个任务, 即下一个任务的开始时间和上一个任务的完成时间间隔固定
        // 以下方法每隔5秒调用一次，并具有固定的延迟，这意味着周期是从前面每次调用的完成时间开始计算的
        // taskRegistrar.addFixedDelayTask(new MyFixedDelayJob(), 5000);
        // taskRegistrar.addFixedDelayTask(new IntervalTask(new MyFixedDelayJob(), 5000, 3000));
    
        // FixedRateTask
        // 特点是上一个任务开始后计时器就开始跑了, 计时器到期并且上一个任务执行完毕才开始下一个任务
        // 注意: 上一个任务开始后, 计时器就开始跑了, 如果上一个任务执行时间大于 interval, 则上一个任务执行完毕后下一个任务立即开始执行
        // taskRegistrar.addFixedRateTask(new MyFixedRateJob(), 1000); // 毫秒
        // taskRegistrar.addFixedRateTask(new IntervalTask(new MyFixedRateJob(), 1000, 3000));
        
        taskRegistrar.addTriggerTask(new TriggerTask(new MyTriggerJob(), triggerContext -> {
            // String cronExpression = "0/3 * * * * ?";
            String cronExpression = fakeCronMapper.getCron();
            Assert.hasText(cronExpression, "cron 表达式不能为空");
            System.out.println("重新获取 cron 表达式: " + cronExpression);
            System.out.println(DateUtil.now() + " 每次执行完任务都会进来, 可以在这里重新读取数据库的cron表达式,实现动态定时任务");
            CronTrigger cronTrigger = new CronTrigger(cronExpression);
            Date nextExecutionTime = cronTrigger.nextExecutionTime(triggerContext);
            return nextExecutionTime;
        }));
    
        // 遍历已注册的任务, 注意有四大定时任务类型
        // List<TriggerTask> triggerTaskList = taskRegistrar.getTriggerTaskList();
        // for (TriggerTask triggerTask : triggerTaskList) {
        //     System.out.println(triggerTask.getTrigger());
        // }
        
        // 任务调度: 尝试立即注册指定的任务 ???
        taskRegistrar.scheduleCronTask(new CronTask(new MyCronJob(), "0/5 * * * * ?"));
        
        // 销毁一切!!!
        // taskRegistrar.destroy();
    }
}
